/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package tetris.model;

import java.util.ArrayList;
import tetris.model.events.FigureActionEvent;
import tetris.model.events.FigureActionListener;
import tetris.model.events.GlassEvent;
import tetris.model.events.GlassListener;
import tetris.model.navigation.Position;

/**
 * Класс стакана.
 * @author vadim
 */
public class Glass implements FigureActionListener{
    private Figure _currentFigure;
    private ArrayList<Figure> _secondFigures;
    private NotEndedRows _notEndedLines;
    private int _height = 20;
    private int _width = 10;
    private int _glassShiftHeight = 0;
    private int _glassShiftWidth = 0;
    private ArrayList<GlassListener> _listeners;
    
    /**
     * Конструктор.
     * @param height высота.
     * @param width ширина.
     */
    public Glass(int height,int width) {
        if (height > 0) {
            _height = height;
        } 
        if (width > 0) {
            _width = width;
        }
        _listeners = new ArrayList<GlassListener>();
        _notEndedLines = new NotEndedRows(this);
        _secondFigures = new ArrayList<Figure>();
    }
    
    /**
     * неоконченные ряды стакана.
     * @return
     */
    public NotEndedRows notEndedLines() {
        return _notEndedLines;
    }

    /**
     * Высота стакана.
     * @return
     */
    public int height() {
        return _height;        
    }
    
    /**
     * Ширина стакана.
     * @return
     */
    public int width() {
        return _width;
    }
    
    /**
     * Добавление слушателя стакана.
     * @param listener слушатель.
     */
    public void addListener(GlassListener listener) {
        _listeners.add(listener);
    }
    
    /**
     * Функция задания текущей фигуры.
     * @param figure фигура.
     */
    public void setCurrentFigure(Figure figure) {
        _currentFigure = figure;
        _currentFigure.setPosition(this, new Position((_height+2),(_width/2)));        
    }
    
    /**
     * Добавленик второй фигуры.
     * @param figure фигура.
     */
    public void addSecondFigure(Figure figure) {
        _secondFigures.add(figure);        
    }
    
    /**
     * Функция удаления заполенных рядов.
     * @return количество удаленных рядов.
     */
    public int removeLines() {
        ArrayList<boolean[]> form = _notEndedLines.form();
        int count = 0;
        for (int i = 0; i < form.size(); i++) {
            boolean isCompleteLine = true;
            for (int j = 0; j < form.get(i).length; j++) {
                if (!form.get(i)[j]) {
                    isCompleteLine = false;
                }
            }
            if (isCompleteLine) {
                count++;
                form.remove(i);
                i--;
            }
        }
        boolean[] row = new boolean[_width];
        for( int j = 0; j < _width; j++) {
            row[j] = false;
        }
        for(int i = 0; i < count; i++)
        {
            _notEndedLines.form().add(row);
        }
        return count;
    }
    
    /**
     * Добавление фигуры к неоконченным рядам стакана.
     * @param figure фигура.
     * @return результат.
     */
    public boolean addFigureToNotEndedLines(Figure figure) {
        int wight = figure.form().get(0).length;
        int modificatorHight = -figure.form().size()/2;
        for(boolean[] cells: figure.form()) {
            if (figure.position().row()-modificatorHight >=0) {
                boolean[] glassCells = notEndedLines().form().get(figure.position().row()-modificatorHight);
                int modificatorWight = -wight/2;
                for(boolean cell: cells) {
                    if (cell) {
                        glassCells[figure.position().column()+modificatorWight] = true;
                    }
                    modificatorWight++;
                }
                notEndedLines().form().set(figure.position().row()-modificatorHight, glassCells.clone());
            }
            modificatorHight++;
        }
        return true;
    }

    /**
     * Сдвиг стакана по высоте на панели.
     * @return
     */
    public int glassShiftHeight() {
        return _glassShiftHeight;
    }
    
    /**
     * Функция задания сдвига стакана по высоте на графической панели.
     * @param value величина сдвига.
     */
    public void setGlassShiftHeight(int value) {
        if(value >= 0) {
            _glassShiftHeight = value;
        }
    }
    
    /**
     * Текущая фигура.
     * @return
     */
    public Figure currentFigure() {
        return _currentFigure;
    }
    
    /**
     * Массив вторых фигур.
     * @return
     */
    public ArrayList<Figure> secondFigures() {
        return _secondFigures;
    }
    
    /**
     * Сдвиг стакана по ширине на графической панели.
     * @return
     */
    public int glassShiftWidth() {
        return _glassShiftWidth;
    }
    
    /**
     * Функция задания сдвига стакана по цирине на граф. панели.
     * @param value велчина сдвига.
     */
    public void setGlassShiftWidth(int value) {
        if(value >= 0) {
            _glassShiftWidth = value;
        }
    }

    /**
     * Реакция стакана на движение фигуры.
     * @param e сообщение фигруы.
     */
    @Override
    public void figureMakedMove(FigureActionEvent e) {
    }

    /**
     * Реакция стакана на поворот фигуры.
     * @param e сообщение фигруы.
     */
    @Override
    public void figureAreTurned(FigureActionEvent e) {
        
    }

    /**
     * Реакция стакана на падение фигуры.
     * @param e сообщение фигруы.
     */
    @Override
    public void figureAreFallen(FigureActionEvent e) {
        addFigureToNotEndedLines((Figure)e.getSource());
        int count = removeLines();
        for(int i = 0; i < _listeners.size(); i++) {
            _listeners.get(i).rowsArranged(new GlassEvent(count));
        }
    }
    
    /**
     * Функция проверки пересечения фигурой границ стакана.
     * @param figure фигура.
     * @return результат.
     */
    public boolean crossing(Figure figure) { 
        boolean result = true;
        int width = figure.form().get(0).length;
        int modificatorHight = figure.form().size() / 2;
        for (boolean[] cells : figure.form()) {
            int modificatorWidth = -width / 2;
            for (boolean cell : cells) {
                if ((_notEndedLines.form().size() <= figure.position().row() + modificatorHight
                        || figure.position().row() + modificatorHight <= 0) && cell) {
                    result = false;
                }
                modificatorWidth++;
            }
            modificatorHight--;
        }
        int maxWidth = 0;
        int minWidth = figure.form().get(0).length;
        for (int i = 0; i < figure.form().size(); i++) {
            for (int j = 0; j < figure.form().get(i).length; j++) {
                if (figure.form().get(i)[j]) {
                    if (j > maxWidth) {
                        maxWidth = j;
                    }
                    if (j < minWidth) {
                        minWidth = j;
                    }
                }
            }
        }
        int temp = width / 2;
        if (figure._glass.width() <= figure._position.column() - temp + maxWidth
               || figure._position.column() - width / 2 + minWidth < 0) {
             result = false;
        }
        if (result) {
            modificatorHight = figure._form.size() / 2;
            for (boolean[] cells : figure._form) {
                int modificatorWidth = -width / 2;
                for (boolean cell : cells) {
                    int number = figure._position.row() + modificatorHight;
                    if (number >= 0) {
                        boolean[] glassCells
                                  = figure._glass.notEndedLines().form().get(number);
                        if ((figure._position.column() + modificatorWidth) >= 0
                                    && (figure._position.column() + modificatorWidth) < glassCells.length
                                    && glassCells[figure._position.column() + modificatorWidth] && cell) {
                                result = false;
                        }
                    }
                    modificatorWidth++;
                }
                modificatorHight--;
            }
        }
        return !result; 
    }
}
